const fs = require('fs')
const path = require('path')
const { saveGResource, saveMeson, saveEntry } = require('./common')

const componentName = process.argv[2]
let componentNameArr = ''

if (!componentName) {
    console.error('Please provide a component name.')
    process.exit(1)
}
if (componentName.includes('_')) {
    componentNameArr = componentName
        .split('_')
        .filter(a => a)
        .map(a => a.toLowerCase())
} else {
    componentNameArr = componentName
        .match(/[A-Z][a-z]*/g)
        .filter(a => a)
        .map(a => a.toLowerCase())
}
if (componentNameArr[0] !== 'component') {
    componentNameArr.unshift('component')
}
const className = componentNameArr.map(a => a.charAt(0).toUpperCase() + a.slice(1)).join('')
const lowerName = componentNameArr.join('_')
const upperName = componentNameArr.map(a => a.toUpperCase()).join('_')
const upperNamespace = componentNameArr[0].toUpperCase()
const upperShortName = componentNameArr
    .slice(1)
    .map(a => a.toUpperCase())
    .join('_')
const upperTypeName = [upperNamespace, 'TYPE', upperShortName].join('_')

const componentPath = path.join(__dirname, '../src', 'components')
const fileNameOfH = path.join(componentPath, `${lowerName}.h`)
fs.writeFileSync(
    fileNameOfH,
    `#pragma once

#include <gtk/gtk.h>

G_BEGIN_DECLS

#define ${upperTypeName} (${lowerName}_get_type())
G_DECLARE_FINAL_TYPE(${className}, ${lowerName}, ${upperNamespace}, ${upperShortName}, GtkBox)

G_END_DECLS
`,
)
const fileNameOfC = path.join(componentPath, `${lowerName}.c`)
fs.writeFileSync(
    fileNameOfC,
    `#include "${lowerName}.h"

struct _${className}
{
    GtkBox parent_instance;
    unsigned int width;
};

enum
{
    PROP_0,
    PROP_WIDTH,
    N_PROPERTIES
};

G_DEFINE_TYPE(${className}, ${lowerName}, GTK_TYPE_WIDGET)
static GParamSpec *obj_properties[N_PROPERTIES] = {
    NULL,
};

static void ${lowerName}_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
    ${className} *self = ${upperName}(object);

    switch (property_id)
    {
    case PROP_WIDTH:
        self->width = g_value_get_uint(value);
        gtk_widget_queue_draw(GTK_WIDGET(self));
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
        return;
    }
}

static void ${lowerName}_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{
    ${className} *self = ${upperName}(object);

    switch (property_id)
    {
    case PROP_WIDTH:
        g_value_set_uint(value, self->width);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
        break;
    }
}

static void ${lowerName}_class_init(${className}Class *klass)
{
    GObjectClass *object_class = G_OBJECT_CLASS(klass);
    object_class->set_property = ${lowerName}_set_property;
    object_class->get_property = ${lowerName}_get_property;

    obj_properties[PROP_WIDTH] = g_param_spec_uint("width", "Width", "Width", 0, G_MAXUINT, 0, G_PARAM_READWRITE);

    g_object_class_install_properties(object_class, N_PROPERTIES, obj_properties);
}

static void ${lowerName}_init(${className} *self)
{
}
`,
)
const fileNameOfUI = path.join(componentPath, `${lowerName}.ui`)
fs.writeFileSync(
    fileNameOfUI,
    `<?xml version="1.0" encoding="UTF-8"?>
<interface>
    <template class="${className}" parent="GtkBox">
        <style>
            <class name="${lowerName}" />
        </style>
    </template>
</interface>
`,
)
const fileNameOfCSS = path.join(componentPath, `${lowerName}.css`)
fs.writeFileSync(
    fileNameOfCSS,
    `.${lowerName} {
    background-color: white;
}
`,
)
saveGResource(lowerName)
saveMeson(lowerName)
saveEntry(lowerName, upperTypeName)
